package com.lzh.excel.imports.processor;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.builder.ExcelReaderSheetBuilder;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.util.IoUtils;
import com.lzh.excel.exception.ErrorCode;
import com.lzh.excel.exception.ExcelException;
import com.lzh.excel.imports.listener.BaseAbstractImportListener;
import org.apache.poi.UnsupportedFileFormatException;
import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.util.RecordFormatException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * @author zhehen.lu
 * @date 2025/8/3 14:33
 */
public abstract class ImportAbstractProcessor<C, R, H> implements IImportProcessor<C, R, H> {
    private static final Logger log = LoggerFactory.getLogger(ImportAbstractProcessor.class);
    private ThreadLocal<Class<H>> headClass = new ThreadLocal();
    private ThreadLocal<MultipartFile> file = new ThreadLocal();

    public ImportAbstractProcessor() {
    }

    @Override
    public R importFile(MultipartFile file, C condition) throws IOException {
        this.file.set(file);
        return this.importFile(file.getInputStream(), condition);
    }

    @Override
    public R importFile(MultipartFile file, C condition, Class<H> headClass) throws IOException {
        this.headClass.set(headClass);
        return this.importFile(file, condition);
    }

    @Override
    public R importFile(InputStream inputStream, C condition) throws IOException {
        Object object;
        try {
            object = this.doImportFile(inputStream, condition);
        } finally {
            if (this.headClass.get() != null) {
                this.headClass.remove();
            }

            if (this.file.get() != null) {
                this.file.remove();
            }

        }

        return (R) object;
    }

    @Override
    public R importFile(InputStream inputStream, C condition, Class<H> headClass) throws IOException {
        this.headClass.set(headClass);
        return this.importFile(inputStream, condition);
    }

    public MultipartFile getFile() {
        return (MultipartFile)this.file.get();
    }

    protected int getSheetNo() {
        return 0;
    }

    protected int getTotalHeadLine() {
        return 1;
    }

    protected R invokeException(ExcelAnalysisException e) {
        throw e;
    }

    protected void invokeFinally(C condition, BaseAbstractImportListener<H> listener) {
    }

    protected void invokeImportBefore(byte[] originSteamBytes, C condition) {
    }

    protected R invokeImportAfter(byte[] originSteamBytes, C condition, BaseAbstractImportListener<H> listener) {
        return null;
    }

    protected R doImportFile(InputStream inputStream, C condition) throws IOException {
        byte[] originSteamBytes = IoUtils.toByteArray(inputStream);
        this.invokeImportBefore(originSteamBytes, condition);
        BaseAbstractImportListener<H> listener = this.getListener(condition);
        ExcelReader excelReader = null;

        label98: {
            Object object;
            try {
                ExcelReaderBuilder read = EasyExcel.read(new ByteArrayInputStream(originSteamBytes), (Class)this.headClass.get(), listener);
                if (this.getSheetNo() == -1) {
                    read.doReadAll();
                } else {
                    excelReader = read.build();
                    ReadSheet readSheet = ((ExcelReaderSheetBuilder)EasyExcel.readSheet(this.getSheetNo()).headRowNumber(this.getTotalHeadLine())).build();
                    excelReader.read(new ReadSheet[]{readSheet});
                }
                break label98;
            } catch (ExcelException | ExcelAnalysisException exception) {
                ExcelAnalysisException excelAnalysisException = new ExcelAnalysisException(exception.getMessage(), exception);
                if (exception instanceof ExcelException) {
                    excelAnalysisException = new ExcelAnalysisException(((ExcelException)exception).getErrorMsg(), exception);
                } else if (exception instanceof ExcelAnalysisException) {
                    excelAnalysisException = (ExcelAnalysisException)exception;
                }

                R response = this.invokeException(excelAnalysisException);
                if (response == null) {
                    break label98;
                }

                object = response;
            } catch (RecordFormatException | RecordInputStream.LeftoverDataException | UnsupportedFileFormatException exception) {
                log.error("excel文件错误：", exception);
                throw new ExcelException(ErrorCode.EXCEL_FILE_FORMAT);
            } finally {
                this.invokeFinally(condition, listener);
                if (excelReader != null) {
                    excelReader.finish();
                }

            }

            return (R) object;
        }

        R res = this.invokeImportAfter(originSteamBytes, condition, listener);
        originSteamBytes = null;
        return res;
    }

    protected abstract BaseAbstractImportListener<H> getListener(C var1);
}
